/**
 *  @file SQLStr.h
 */
#ifndef _SQLSTR_H_
#define _SQLSTR_H_

#include "../common/BaseObject.h"
#include "../text/CFString.h"
#include "../collections/ArrayT.h"
#include "../collections/ListT.h"

namespace cppflib
{

namespace database
{


/**
 *  Helper class to generate SQL statements
 */
class _DLLAPI SQLStr
{
private:
   SQLStr() {}

public:
   ~SQLStr() {}


   /**
    * Base interface for the 2 classes below
    */ 
   class _DLLAPI SQLBaseClause : public BaseObject
   {
   protected:
      SQLBaseClause() { }
   public:
      virtual ~SQLBaseClause() { };
      virtual void GenString(CFString &sb) = 0;
   };

   /**
    *  A class to wrap around statement with brackets like
    *    --  (x = 'apple' or y > 9) and u = 11
    *    --  (x = 'apple' or y > 9) and (u = 11 or a = 'haha')
    */
   class _DLLAPI SQLCondClause : public SQLBaseClause
   {
   private:
      SQLBaseClause *cond1;   ///< a SqlCondClause or a SqlSimpCond
      CFString op;      ///< operation string, e.g. "=", "<", ">"
      SQLBaseClause *cond2;   ///< a SqlCondClause or a SqlSimpCond

   private:
      SQLCondClause() { }
      void ProcessCond(CFString &sb, SQLBaseClause *cond);

   public:
      SQLCondClause(SQLBaseClause *cond1, const CFString &op, SQLBaseClause *cond2);
      virtual ~SQLCondClause();
      virtual void GenString(CFString &sb);
   };


   /**
    *  A class to wrap around a simple condition statement like
    *      --  x = 5
    *      --  y = 'earth'
    *      --  z > 90
    *  or just a single keyword:
    *      -- 'and'
    *      -- 'like'
    */
   class _DLLAPI SQLSimpCond : public SQLBaseClause
   {
   private:
      CFString name;    ///< left to op string
      CFString op;      ///< operation string, e.g. "=", "<", ">"
      BaseObject *value; ///< right to op string (CFString, Int32, Int64, UInt32, UInt64, DateTime or PlaceHolder)

   private:
      SQLSimpCond() { }

   public:
      SQLSimpCond(const CFString &op);  // fill in single keyword only 
      SQLSimpCond(const CFString &name, const CFString &op, BaseObject *value);
      virtual ~SQLSimpCond();
      virtual void GenString(CFString &sb);
   };

   /**
    *  Place holder
    */
   class _DLLAPI PlaceHolder : public BaseObject
   {
   private:
      CFString placeHolderName;

   private:
      PlaceHolder() { }
   
   public:
      explicit PlaceHolder(const CFString &name);
      const CFString& GetName() const;
      virtual pcwstr_t ToString(void) const;
   };


public:
   PUBLIC const CFString *GenCreateTable(const CFString &tabName, collections::ListCppObjT<CFString> &colsAndTypes);
   PUBLIC const CFString *GenDropTable(const CFString &tabName);
   PUBLIC const CFString *GenSelect(const CFString &tabName, collections::ListCppObjT<CFString> &cols, const CFString &whereClause, 
                                    const CFString &groupBy, const CFString &having, const CFString &orderBy);
   PUBLIC const CFString *GenSelectWithRowid(const CFString &tabName, collections::ListCppObjT<CFString> &cols,
                                             const CFString &whereClause);
   PUBLIC const CFString *GenInsert(const CFString &tabName, collections::ListCppObjT<BaseObject> &colsAndValues);
   PUBLIC const CFString *GenUpdate(const CFString &tabName, collections::ListCppObjT<BaseObject> &colsAndValues, const CFString &whereClause);
   PUBLIC const CFString *GenDelete(const CFString &tabName, const CFString &whereClause);
   PUBLIC const CFString *GenWhere(collections::ListCppObjT<SQLBaseClause> &values);
   

};

} // end of namespace database

} // end of namespace cppflib


#endif
